package mse.eai.esb;

import java.util.Map;

import org.jboss.logging.Logger;
import org.jboss.soa.esb.actions.ActionLifecycle;
import org.jboss.soa.esb.actions.ActionLifecycleException;
import org.jboss.soa.esb.addressing.EPR;
import org.jboss.soa.esb.addressing.PortReference;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.message.Body;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.services.jbpm.Constants;
import org.jboss.soa.esb.services.jbpm.JBpmObjectMapper;
import org.jboss.soa.esb.services.jbpm.cmd.CallbackCommand;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.db.GraphSession;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
import org.jbpm.graph.exe.Token;

public class SignalProcessAction implements ActionLifecycle {

	private static final Logger log = Logger
			.getLogger(SignalProcessAction.class);

	private ConfigTree configTree;

	@Override
	public void destroy() throws ActionLifecycleException {
		// TODO Auto-generated method stub

	}

	@Override
	public void initialise() throws ActionLifecycleException {
		// TODO Auto-generated method stub

	}

	public SignalProcessAction(ConfigTree config) {

		configTree = config;
	}

	public Message process(Message message) {
		log.info("ESB Action start ------>");

		log.info("Preparing to signal process");

		JbpmConfiguration jbpmConf = JbpmConfiguration.getInstance();

		// Open the transaction.
		JbpmContext jbpmCtx = jbpmConf.createJbpmContext();

		try {

			GraphSession graphSession = jbpmCtx.getGraphSession();

			ProcessDefinition processDefinition = graphSession
					.findLatestProcessDefinition((String) message.getBody()
							.get("processDefinitionName"));

			log.info("PROCESS DEFINITION FOUND " + processDefinition);

			log.info("NOW GETTING THE INSTANCE "
					+ (String) message.getBody().get("processKey"));

			ProcessInstance instance = graphSession.getProcessInstance(
					processDefinition,
					(String) message.getBody().get("processKey"));
			// String transitionName = (String)
			// message.getBody().get("transition");

			if (instance != null) {

				Token token = instance.getRootToken();

				final EPR epr = new EPR();
				final PortReference portRef = epr.getAddr();
				final long nodeId = token.getNode().getId();
				final long tokenId = token.getId();
				final long processVersion = instance.getProcessDefinition()
						.getVersion();

				log.info("token locked = " + token.isLocked());

				portRef.addExtension(Constants.NODE_ID, String.valueOf(nodeId));
				portRef.addExtension(Constants.TOKEN_ID,
						String.valueOf(tokenId));
				portRef.addExtension(Constants.PROCESS_INSTANCE_ID,
						String.valueOf(instance.getId()));

				// Set the counter
				String counterName = Constants.PROCESS_NODE_VERSION_COUNTER
						+ nodeId + '_' + tokenId;
				portRef.addExtension(counterName,
						String.valueOf(processVersion));

				// Get esbToBpmVars
				String esbToBpmVars = "<property name=\"esbToBpmVars\"> ";
				for (ConfigTree current : configTree.getChildren("mapping")) {
					esbToBpmVars += current.toString();
					esbToBpmVars += " ";
				}
				esbToBpmVars += "</property> ";

				// Get transition
				// String transitionNameString =
				// "<property name=\"transition-name\"> ";
				// for (ConfigTree current : configTree.getChildren("mapping"))
				// {
				// }
				// esbToBpmVars += "</property> ";

				portRef.addExtension(Constants.ESB_TO_BPM_VARS_TAG,
						esbToBpmVars);
				// log.info("children =" + esbToBpmVars);

				// Obtaining the VariableMap that is going to be set callback
				// command
				JBpmObjectMapper mapper = new JBpmObjectMapper();
				Map<String, Object> variableMap = mapper
						.mapFromEsbMessageToJBpmMap(message, esbToBpmVars);
				if (null != variableMap) {
					message.getBody().add(Constants.VARIABLE_VALUES,
							variableMap);
				}
				// log.info("esbToBpmVars = " + variableMap);

				// the above for setting esbToBpm variables into message body
				// wouldn't work because
				// the processing in CallbackCommand.java need it to be called
				// from EsbActionHandler
				// our case is not called by EsbActionHandler.

				// add the esbToBpmVars to jbpm (this one can set the variables
				// correctly)
				if (variableMap != null)
					for (Map.Entry<String, Object> entry : variableMap
							.entrySet()) {
						instance.getContextInstance().setVariableLocally(
								entry.getKey(), entry.getValue());
					}

				// The counterName variable is expected to be found in the
				// process context.
				instance.getContextInstance().setVariableLocally(counterName,
						processVersion);

				message.getHeader().getCall().setTo(epr);

				// test callback
				CallbackCommand callback = new CallbackCommand();
				callback.setCallbackEpr(epr);
				callback.setMessage(message);
				callback.execute(jbpmCtx);

				// token.signal();
				log.info("Process signaled.");

			}

		} catch (Exception e) {
			log.error(e);
		} finally {
			// Close context.
			jbpmCtx.close();
		}

		log.info("Done");

		log.info("<------- ESB Action done");
		return message;

	}
}
